package ssau.knyazev.fft.modules.threads;

import ssau.knyazev.core.B2Complex;
import ssau.knyazev.core.CComplex;
import ssau.knyazev.core.Complex;

public class B2ComplexAlgThread implements Runnable {

	protected int idx;
	protected int idy;
	protected int uid;
	protected int blockX;
	protected int blockY;
	private B2Complex[][] data = null;
	private B2Complex[] wilist = null;
	private B2Complex[] wjlist = null;
	private boolean isU0U2 = false;
	
	public B2ComplexAlgThread(B2Complex[][] data, B2Complex[] wilist, B2Complex[] wjlist, boolean isU0U2){
		this.data = data;
		this.wilist = wilist;
		this.wjlist = wjlist;
		this.isU0U2 = isU0U2;
	}
	
	public void run(){
		int N = data.length;
		int size = 0;
		for (int x = data.length; x > 1; x = x >> 1){
			size++;
		}
		if (isU0U2){
			for (int q = 0; q < size; q++) {
				int step = 1 << q;
				int step2 = step << 1;
				for (int down = 0; down < N - step; down++) {
					for (int right = 0; right < N - step; right++) {
						boolean flag = (down/step) % 2 + (right/step) % 2 > 0 ? false : true;
						if (flag) {
							B2Complex w1 = wilist[(down % step2)*(N/step2)];
							B2Complex w2 = wjlist[(right % step2)*(N/step2)];
							fft2d2x2U0U2(data[down][right], data[down][right + step], data[down + step][right], data[down + step][right + step], w1, w2);
						}
					}
				}
			}
		} else {
			for (int q = 0; q < size; q++) {
				int step = 1 << q;
				int step2 = step << 1;
				for (int down = 0; down < N - step; down++) {
					for (int right = 0; right < N - step; right++) {
						boolean flag = (down/step) % 2 + (right/step) % 2 > 0 ? false : true;
						if (flag) {
							B2Complex w1 = wilist[(down % step2)*(N/step2)];
							B2Complex w2 = wjlist[(right % step2)*(N/step2)];
							fft2d2x2U1U3(data[down][right], data[down][right + step], data[down + step][right], data[down + step][right + step], w1, w2);
						}
					}
				}
			}
		}
	}
	
	private static void fft2d2x2U1U3(B2Complex a00, B2Complex a01, B2Complex a10, B2Complex a11, B2Complex wi, B2Complex wj) {
		B2Complex newa00 = new B2Complex();
		B2Complex newa01 = new B2Complex();
		B2Complex newa10 = new B2Complex();
		B2Complex newa11 = new B2Complex();

		newa00 = B2Complex.sumU1U3(newa00, a00);
		newa10 = B2Complex.sumU1U3(newa10, a00);
		newa01 = B2Complex.sumU1U3(newa01, a00);
		newa11 = B2Complex.sumU1U3(newa11, a00);
		
		B2Complex t = B2Complex.multyU1U3(wi, a10);
		newa00 = B2Complex.sumU1U3(newa00, t);
		newa10 = B2Complex.subU1U3(newa10, t);
		newa01 = B2Complex.sumU1U3(newa01, t);
		newa11 = B2Complex.subU1U3(newa11, t);
		
		t = B2Complex.multyU1U3(wj, a01);
		newa00 = B2Complex.sumU1U3(newa00, t);
		newa10 = B2Complex.sumU1U3(newa10, t);
		newa01 = B2Complex.subU1U3(newa01, t);
		newa11 = B2Complex.subU1U3(newa11, t);
		
		t = B2Complex.multyU1U3(wj, a11);
		t = B2Complex.multyU1U3(wi, t);
		newa00 = B2Complex.sumU1U3(newa00, t);
		newa10 = B2Complex.subU1U3(newa10, t);
		newa01 = B2Complex.subU1U3(newa01, t);
		newa11 = B2Complex.sumU1U3(newa11, t);

		copyValuesU1U3(a00, newa00);
		copyValuesU1U3(a01, newa01);
		copyValuesU1U3(a10, newa10);
		copyValuesU1U3(a11, newa11);
	}
	
	private static void fft2d2x2U0U2(B2Complex a00, B2Complex a01, B2Complex a10, B2Complex a11, B2Complex wi, B2Complex wj) {
		B2Complex newa00 = new B2Complex();
		B2Complex newa01 = new B2Complex();
		B2Complex newa10 = new B2Complex();
		B2Complex newa11 = new B2Complex();

		newa00 = B2Complex.sumU0U2(newa00, a00);
		newa10 = B2Complex.sumU0U2(newa10, a00);
		newa01 = B2Complex.sumU0U2(newa01, a00);
		newa11 = B2Complex.sumU0U2(newa11, a00);
		
		B2Complex t = B2Complex.multyU0U2(wi, a10);
		newa00 = B2Complex.sumU0U2(newa00, t);
		newa10 = B2Complex.subU0U2(newa10, t);
		newa01 = B2Complex.sumU0U2(newa01, t);
		newa11 = B2Complex.subU0U2(newa11, t);
		
		t = B2Complex.multyU0U2(wj, a01);
		newa00 = B2Complex.sumU0U2(newa00, t);
		newa10 = B2Complex.sumU0U2(newa10, t);
		newa01 = B2Complex.subU0U2(newa01, t);
		newa11 = B2Complex.subU0U2(newa11, t);
		
		t = B2Complex.multyU0U2(wj, a11);
		t = B2Complex.multyU0U2(wi, t);
		newa00 = B2Complex.sumU0U2(newa00, t);
		newa10 = B2Complex.subU0U2(newa10, t);
		newa01 = B2Complex.subU0U2(newa01, t);
		newa11 = B2Complex.sumU0U2(newa11, t);

		copyValuesU0U2(a00, newa00);
		copyValuesU0U2(a01, newa01);
		copyValuesU0U2(a10, newa10);
		copyValuesU0U2(a11, newa11);
	}

	private static void copyValuesU0U2(B2Complex a, B2Complex b) {
		a.setU0(b.getU0());
		a.setU2(b.getU2());
	}
	
	private static void copyValuesU1U3(B2Complex a, B2Complex b) {
		a.setU1(b.getU1());
		a.setU3(b.getU3());
	}
	
}
